package com.imooc.security.browser;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.social.security.SpringSocialConfigurer;

import com.imooc.security.core.authentication.FormAuthenticationConfig;
import com.imooc.security.core.authentication.mobile.SmsCodeAuthenticationSecurityConfig;
import com.imooc.security.core.properties.SecurityConstants;
import com.imooc.security.core.properties.SecurityProperties;
import com.imooc.security.core.validate.code.ValidateCodeSecurityConfig;

/**
 * 5.9.12 重构10
 * 浏览器环境下安全配置主类
 */
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private SecurityProperties securityProperties;
	
	@Autowired
	private DataSource dataSource;
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Autowired
	private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;
	
	@Autowired
	private ValidateCodeSecurityConfig validateCodeSecurityConfig;
	
	@Autowired
	private SpringSocialConfigurer imoocSocialSecurityConfig;
	
	@Autowired
	private SessionInformationExpiredStrategy sessionInformationExpiredStrategy;
	
	@Autowired
	private InvalidSessionStrategy invalidSessionStrategy;

	@Autowired
	private FormAuthenticationConfig formAuthenticationConfig;
	
	@Autowired
	private LogoutSuccessHandler logoutSuccessHandler;
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		
		formAuthenticationConfig.configure(http);
		
		http.apply(validateCodeSecurityConfig)
				.and()
			.apply(smsCodeAuthenticationSecurityConfig)
				.and()
			.apply(imoocSocialSecurityConfig)
				.and()
			//记住我配置，如果想在'记住我'登录时记录日志，可以注册一个InteractiveAuthenticationSuccessEvent事件的监听器
			.rememberMe()
				.tokenRepository(persistentTokenRepository())
				.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
				.userDetailsService(userDetailsService)
				.and()
			.sessionManagement()
				.invalidSessionStrategy(invalidSessionStrategy)
				.maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())
				.maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())
				.expiredSessionStrategy(sessionInformationExpiredStrategy)
				.and()
				.and()
			// 5.11.2 配置退出登录
			.logout()
				.logoutUrl("/signOut")
				// 5.11.7 改成handler方式，配置了url就不能配handler
				// .logoutSuccessUrl("/imooc-logout.html")
				.logoutSuccessHandler(logoutSuccessHandler)
				.deleteCookies("JSESSIONID")
				.and()

			.authorizeRequests()
				.antMatchers(
					SecurityConstants.DEFAULT_UNAUTHENTICATION_URL,
					securityProperties.getBrowser().getSignInPage(),
					SecurityConstants.DEFAULT_VALIDATE_CODE_URL_PREFIX+"/*",
					securityProperties.getBrowser().getSignUpUrl(),
					securityProperties.getBrowser().getSession().getSessionInvalidUrl(),
					"/user/regist")
					.permitAll()
				.anyRequest()
				.authenticated()
				.and()
			.csrf().disable();
	}

	/**
	 * 记住我功能的token存取器配置
	 * @return
	 */
	@Bean
	public PersistentTokenRepository persistentTokenRepository() {
		JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
		tokenRepository.setDataSource(dataSource);
//		tokenRepository.setCreateTableOnStartup(true);
		return tokenRepository;
	}
	
}

/*import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.social.security.SpringSocialConfigurer;

import com.imooc.security.browser.session.ImoocExpiredSessionStrategy;
import com.imooc.security.core.authentication.FormAuthenticationConfig;
import com.imooc.security.core.authentication.mobile.SmsCodeAuthenticationSecurityConfig;
import com.imooc.security.core.properties.SecurityConstants;
import com.imooc.security.core.properties.SecurityProperties;
import com.imooc.security.core.validate.code.ValidateCodeSecurityConfig;

*//**
 * 4.12.6 3重构 配置分离 浏览器的归浏览器
 * 浏览器环境下安全配置主类
 *//*
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private SecurityProperties securityProperties;
	
	@Autowired
	private DataSource dataSource;
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Autowired
	private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;
	
	@Autowired
	private ValidateCodeSecurityConfig validateCodeSecurityConfig;
	
	@Autowired
	private FormAuthenticationConfig formAuthenticationConfig;
	
	@Autowired
	private SpringSocialConfigurer imoocSocialSecurityConfig;
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		
		formAuthenticationConfig.configure(http);
		
		http.apply(validateCodeSecurityConfig)
				.and()
			.apply(smsCodeAuthenticationSecurityConfig)
				.and()
			// 5.4.20 应用social配置，作用是过滤器链上添加一个社交过滤器，当用户访问时引导用户登录
			.apply(imoocSocialSecurityConfig)
				.and()
			//记住我配置，如果想在'记住我'登录时记录日志，可以注册一个InteractiveAuthenticationSuccessEvent事件的监听器
			.rememberMe()
				.tokenRepository(persistentTokenRepository())
				.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
				.userDetailsService(userDetailsService)
				.and()
			
			// 5.9.3 配置session管理器，针对session失效返回特定的失败json
			.sessionManagement()
				.invalidSessionUrl("/session/invalid")
					// 5.9.7 配置最大session数，实现踢人功能
					.maximumSessions(1)
					// 5.9.11 实现已经登录不让同一个用户登录
					.maxSessionsPreventsLogin(true)
					// 5.9.10 配置session失效处理策略
					.expiredSessionStrategy(new ImoocExpiredSessionStrategy())
					.and()
				.and() // 2个and编译就不会报错
				
			.authorizeRequests()
				.antMatchers(
					SecurityConstants.DEFAULT_UNAUTHENTICATION_URL,
					securityProperties.getBrowser().getLoginPage(),
					// "/code/*") // 4.12.6 11重构 参数标准化
					SecurityConstants.DEFAULT_VALIDATE_CODE_URL_PREFIX+"/*",
					// 5.6.6 添加社交注册页权限，微信qq通用
					securityProperties.getBrowser().getSignUpUrl(),
					// 5.6.12 添加社交注册/绑定权限，微信qq通用
					"/user/regist",
					// 5.9.5 添加session失效权限
					"/session/invalid")
					.permitAll()
				.anyRequest()
				.authenticated()
				.and()
			.csrf().disable();
	}

	*//**
	 * 记住我功能的token存取器配置
	 * @return
	 *//*
	@Bean
	public PersistentTokenRepository persistentTokenRepository() {
		JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
		tokenRepository.setDataSource(dataSource);
		// tokenRepository.setCreateTableOnStartup(true);
		return tokenRepository;
	}
	
}*/

/*import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import com.imooc.security.core.authentication.mobile.SmsCodeAuthenticationSecurityConfig;
import com.imooc.security.core.properties.SecurityProperties;
import com.imooc.security.core.validate.code.SmsCodeFilter;
import com.imooc.security.core.validate.code.ValidateCodeFilter;

*//**
 * 4.9.8 rememberMe源码解读
 * UsernamePasswordAuthenticationFilter 70
 * AbstractAuthenticationProcessingFilter 318
 * PersistentTokenBasedRememberMeServices 167
 * 
 * RememberMeAuthenticationFilter 98
 * AbstractRememberMeServices 130
 * PersistentTokenBasedRememberMeServices 103
 * PersistentTokenBasedRememberMeServices 150
 *//*
*//**
 * 4.2.2 添加BrowerSecurityConfig配置类
 * 
 * @author qilongfei
 *
 *//*
@Configuration
public class BrowerSecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Autowired
	private SecurityProperties securityProperties;

	@Autowired
	private AuthenticationSuccessHandler imoocAuthenctiationSuccessHandler;

	@Autowired
	private AuthenticationFailureHandler imoocAuthenctiationFailureHandler;

	@Autowired
	private DataSource dataSource;

	@Autowired
	private UserDetailsService userDetailsService;
	
	@Autowired
	private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;

	*//**
	 * 4.3.3 自定义加密类 只要加了Bean就会成为默认的encoder 每次加密出来的不一样
	 * 
	 * @return
	 *//*
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	*//**
	 * 4.2.3 添加http安全配置
	 *//*
	@Override
	protected void configure(HttpSecurity http) throws Exception {

		// 4.7.15 生成过滤器，并关联自定义错误处理器
		ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
		validateCodeFilter.setAuthenticationFilterHandler(imoocAuthenctiationFailureHandler);
		// 4.8.7 手动执行bean初始化方法(因为没用注解)
		validateCodeFilter.setSecurityProperties(securityProperties);
		validateCodeFilter.afterPropertiesSet();
		
		// 4.12.3 创建短信过滤器，区别于短信认证过滤器 SmsCodeAuthenticationFilter
		SmsCodeFilter smsCodeFilter = new SmsCodeFilter();
		smsCodeFilter.setAuthenticationFilterHandler(imoocAuthenctiationFailureHandler);
		smsCodeFilter.setSecurityProperties(securityProperties);
		smsCodeFilter.afterPropertiesSet();

		http
			.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 4.7.14 注册自定义过滤器
			.addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class) // 4.12.4 注册短信过滤器
			
			.formLogin()
				// .loginPage("/imooc-signIn.html") // 4.4.1 自定义登录页面
				.loginPage("/authentication/require") // 4.4.8 自定义登录跳转
				.loginProcessingUrl("/authentication/form") // 4.4.4 自定义登录url
				.successHandler(imoocAuthenctiationSuccessHandler) // 4.5.3 自定义登录成功处理
				.failureHandler(imoocAuthenctiationFailureHandler) // 4.5.6 自定义登录失败处理

			// 4.9.6 配置rememberMe	
			.and().rememberMe().
				tokenRepository(persistentTokenRepository())
				.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
				.userDetailsService(userDetailsService)

		// http.httpBasic()
			.and().authorizeRequests()
				// .antMatchers("/imooc-signIn.html").permitAll() // 4.4.2 添加自定义登录页访问权限
				.antMatchers("/authentication/require", // 4.4.9 自定义登录跳转权限
						securityProperties.getBrowser().getLoginPage(), // 4.4.18  配置的自定义登录页访问权限
						// "/code/image" // 4.7.8 添加验证码权限
						"/code/*" // 4.10.20 改成通用的验证码
						).permitAll().anyRequest().authenticated()

			.and().csrf() // 4.4.5 关闭csrf防护
				.disable()
			
			.apply(smsCodeAuthenticationSecurityConfig); // 4.12.5 引用局部配置 短信认证相关配置（达到既可以用短信验证码登录也可以用用户名密码登录）
	}
	
	*//**
	 * 4.9.3 配置记住我repository持久化对象
	 *//*
	@Bean
	public PersistentTokenRepository persistentTokenRepository() {
		JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
		tokenRepository.setDataSource(dataSource);
		// 在启动的时候创建一张表
		// 4.9.7 启动一次自动生成表后注释掉
		// tokenRepository.setCreateTableOnStartup(true);
		return tokenRepository;
	}

}*/
